import sys

import wmi
from PySide6 import QtWidgets, QtCore, QtGui
from PySide6.QtCore import QThread, Signal, QRegularExpression, QTimer
from PySide6.QtGui import QIcon, QTextCursor
from PySide6.QtWidgets import QApplication, QMainWindow, QMessageBox, QGraphicsScene
from serial import PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, \
    STOPBITS_TWO, FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS

from DrawLine import DrawLine
from ui_SerialTool import Ui_MainWindow
from SerialThread import SerialThread
from ScanerThread import ScanerThread

from time import sleep

import serial
import serial.tools.list_ports
import re

BYTESIZES = (EIGHTBITS,SEVENBITS, SIXBITS,FIVEBITS)
PARITIES = (PARITY_NONE, PARITY_EVEN,PARITY_MARK, PARITY_ODD)
STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)
ENCODES = ('utf-8', 'gb2312', 'big5')



class MyWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        # SET AS GLOBAL WIDGETS
        # ///////////////////////////////////////////////////////////////
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.conFig = 0
        self.ports = serial.tools.list_ports.comports()
        self.select_port = self.ports[0].device
        self.serial_thread = None
        self.scaner_thread = None
        self.sendHexViable = True
        self.sendHexFig = self.ui.checkBox_sendHex.isChecked()
        self.recHexFig = self.ui.checkBox_recHex.isChecked()

        self.ui.comboBox_baud.setCurrentIndex(11)
        # self.ui.tabWidget.setCurrentIndex(1)
        self.ui.graphicsView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.ui.graphicsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        #设置Button_clear按键上文字的字体颜色为绿色
        self.ui.Button_clear.setStyleSheet("color: rgb(65, 77, 241); border : none;")

        for port in self.ports:
            self.ui.comboBox_port.addItem(port.device)
        # self.send_port_name_to_port()
        ## 连接信号槽
        self.ui.comboBox_port.view().entered.connect(lambda index: self.show_tooltip(self.ui.comboBox_port, index))
        self.ui.Button_connect.clicked.connect(self.connect_port)
        self.ui.Button_send.clicked.connect(self.send_data)
        self.ui.Button_refresh.clicked.connect(self.refresh_port)
        self.ui.checkBox_sendHex.clicked.connect(self.change_send_checkBox)
        self.ui.checkBox_recHex.clicked.connect(self.change_rec_checkBox)
        self.ui.Button_clear.clicked.connect(self.clear_data)
        self.ui.plainTextEdit_send.textChanged.connect(self.edit_send_data)
        self.ui.tabWidget.currentChanged.connect(self.tab_change)


        # 创建一个QGraphicsScene和QGraphicsView
        self.scene = QGraphicsScene()
        self.dl = DrawLine()
        self.scene.addWidget(self.dl.createPlot())
        self.ui.graphicsView.setScene(self.scene)


        # 开启扫描线程
        self.scaner_thread = ScanerThread()
        self.scaner_thread.port_signal.connect(self.scaner_thread_signal)
        self.scaner_thread.start()

    def tab_change(self):
        if self.ui.tabWidget.currentIndex() == 1:
            # self.ui.graphicsView.setScene(self.scene)
            self.dl.resize(self.ui.graphicsView.width(), self.ui.graphicsView.height())

    def scaner_thread_signal(self,port_list):
        print("硬件变化")
        self.refresh_port()

    def resizeEvent(self, event):
        self.dl.resize(self.ui.graphicsView.width(), self.ui.graphicsView.height())
        # print(self.ui.graphicsView.geometry())

    def edit_send_data(self):
        if self.sendHexFig:
            text = self.ui.plainTextEdit_send.toPlainText()
            text = text.replace(' ','')
            regx = QRegularExpression('^[0-9A-Fa-f]*$')
            # print(regx.match(text))
            if regx.match(text).hasMatch():
                if len(text)%2 == 0:
                    self.sendHexViable = True
                    self.ui.plainTextEdit_send.setStyleSheet("color: rgb(65, 77, 241);")
                else:
                    self.sendHexViable = False
                    self.ui.plainTextEdit_send.setStyleSheet("color: rgb(255, 0, 0);")
            else:
                self.sendHexViable = False
                self.ui.plainTextEdit_send.setStyleSheet("color: rgb(255, 0, 0);")


    def clear_data(self):
        self.ui.textBrowser_rec.clear()

    def change_rec_checkBox(self):
        self.recHexFig = self.ui.checkBox_recHex.isChecked()
    def change_send_checkBox(self):
        self.sendHexFig = self.ui.checkBox_sendHex.isChecked()
        if self.sendHexFig:
            text = bytes(self.ui.plainTextEdit_send.toPlainText(),"utf-8").decode("unicode_escape")
            self.ui.plainTextEdit_send.clear()
            hex_string = self.string_to_hex(text).upper()
            formatted_hex = ' '.join(hex_string[i:i+2] for i in range(0, len(hex_string), 2))
            self.ui.plainTextEdit_send.setPlainText(formatted_hex)
        else:
            text = self.ui.plainTextEdit_send.toPlainText()
            string = self.send_hex_to_string(text)
            self.ui.plainTextEdit_send.clear()
            self.ui.plainTextEdit_send.setStyleSheet("color: rgb(0, 0, 0);")
            self.ui.plainTextEdit_send.setPlainText(string)

    def string_to_hex(self,string):
        # 将字符串编码为字节
        byte_string = string.encode('utf-8')
        # 将字节转换为十六进制字符串
        hex_string = byte_string.hex()
        return hex_string

    def rec_hex_to_string(self,hex_string):
        # 将十六进制字符串转换为字节
        byte_string = bytes.fromhex(hex_string)
        # 将字节转换为字符串
        try :
            string = byte_string.decode('utf-8')
        except :
            self.message("错误","接收数据超出编码范围")
            if self.ui.checkBox_recHex.isChecked() == False:
                self.ui.checkBox_recHex.setChecked(True)
                self.recHexFig = True
            string = hex_string
        return string
    def send_hex_to_string(self,hex_string):
        # 将十六进制字符串转换为字节
        byte_string = bytes.fromhex(hex_string)
        # 将字节转换为字符串
        try :
            string = byte_string.decode('utf-8')
        except :
            self.message("错误","该数据超出编码范围")
            if self.ui.checkBox_sendHex.isChecked()==False:
                self.ui.checkBox_sendHex.setChecked(True)
            string = hex_string
        return string

    def show_tooltip(self,widget, index):
        # 获取项目数据
        model = self.ui.comboBox_port.model()
        index = model.index(index.row(), 0)
        tooltip = self.ports[index.row()].description
        # 显示工具提示
        widget.setToolTip(tooltip)

    def connect_port(self):
        if self.ui.comboBox_port.currentText() == "":
            self.message("错误","请选择串口")
        elif self.conFig == 1 :
            self.conFig = 0
            self.ui.Button_connect.setText("打开")
            self.ui.Button_connect.setStyleSheet("background-color: rgb(255, 255, 255);")
            # self.serial.close()
            # self.message("已断开", "已断开")
            # 禁止设置区域的各项设置
            self.ui.comboBox_port.setEnabled(True)
            self.ui.comboBox_baud.setEnabled(True)
            self.ui.comboBox_datebit.setEnabled(True)
            self.ui.comboBox_parity.setEnabled(True)
            self.ui.comboBox_stopbit.setEnabled(True)
            self.ui.Button_refresh.setEnabled(True)
            self.serial_thread.stop()
            self.serial_thread = None
        else:
            self.conFig = 1
            self.ui.Button_connect.setText("断开")
            self.ui.Button_connect.setStyleSheet("background-color: rgb(65, 241, 229);")
            port = self.ui.comboBox_port.currentText()
            self.select_port = port
            print(port)
            baud = int(self.ui.comboBox_baud.currentText())
            print(baud)
            datebit = BYTESIZES[self.ui.comboBox_datebit.currentIndex()]
            print(datebit)
            parity = PARITIES[self.ui.comboBox_parity.currentIndex()]
            print(parity)
            stopbit = STOPBITS[self.ui.comboBox_stopbit.currentIndex()]
            print(stopbit)
            # try:
            #     self.serial = serial.Serial(port, baud, datebit, parity, stopbit,timeout=1)
            #     print("已连接")
            # except serial.SerialException as e:
            #     print(e)
            #     print("串口打开失败")
            # 禁止设置区域的各项设置
            self.ui.comboBox_port.setEnabled(False)
            self.ui.comboBox_baud.setEnabled(False)
            self.ui.comboBox_datebit.setEnabled(False)
            self.ui.comboBox_parity.setEnabled(False)
            self.ui.comboBox_stopbit.setEnabled(False)
            self.ui.Button_refresh.setEnabled(False)
            # 开启接收线程
            self.serial_thread = SerialThread(port, baud, datebit, parity, stopbit)
            #设置线程确保程序退出时自动关闭线程
            self.serial_thread.data_signal.connect(self.rec_data_show)
            self.serial_thread.start()



    def rec_data_show(self,data):
        # print(data)
        rec_data = self.rec_hex_to_string(data)
        rec_data = rec_data.split(',')
        for i in rec_data:
            if i!='':
                self.dl.update(float(i))
        # print(rec_data)
        cursor = self.ui.textBrowser_rec.textCursor()
        cursor.movePosition(QTextCursor.End)
        if self.recHexFig:
            # text = data.decode("unicode_escape")
            # hex_string = self.string_to_hex(text).upper()
            # formatted_hex = ' '.join(hex_string[i:i + 2] for i in range(0, len(hex_string), 2))
            formatted_hex = ' '.join(data[i:i + 2] for i in range(0, len(data), 2))
            cursor.insertText(formatted_hex+" ")
        else:
            cursor.insertText(self.rec_hex_to_string(data))
        self.ui.textBrowser_rec.setTextCursor(cursor)

    def refresh_port(self):
        self.ports = serial.tools.list_ports.comports()
        self.ui.comboBox_port.clear()
        for port in self.ports:
            self.ui.comboBox_port.addItem(port.device)
        if self.ui.comboBox_port.findText(self.select_port) == -1:  #如果连接的设备异常退出，断开连接，否则插拔设备时保持连接
            self.select_port = self.ui.comboBox_port.itemText(0)
            if self.conFig == 1:
                self.connect_port()
            print("退出连接")
        else :
            self.ui.comboBox_port.setCurrentText(self.select_port)


    def send_data(self):
        if self.conFig == 1:
            try:
                if self.serial_thread:
                    if self.sendHexFig == False:
                        sendtext = bytes(self.ui.plainTextEdit_send.toPlainText(),"utf-8").decode("unicode_escape")
                        self.serial_thread.serial_conn.write(bytes(sendtext,"utf-8"))
                        print(sendtext)
                    else:
                        if self.sendHexViable == False:
                            self.message("错误","请输入正确的十六进制数据")
                        else:
                            sendtext = bytes.fromhex(self.ui.plainTextEdit_send.toPlainText())
                            print(sendtext)
                            self.serial_thread.serial_conn.write(sendtext)
                    print("发送成功")
            except serial.SerialException as e:
                print(e)
                print("串口发送失败")


    def message(self, title, text):
        message = QMessageBox()
        message.setWindowTitle(str(title))
        message.setText(str(text))
        message.setStandardButtons(QMessageBox.StandardButton.Ok)
        message.setDefaultButton(QMessageBox.StandardButton.Ok)
        if message.exec() == QMessageBox.StandardButton.Ok:
            # print(str(text))
            pass

    def closeEvent(self, event: QtGui.QCloseEvent) -> None:
        if self.serial_thread:
            self.serial_thread.stop()
            self.serial_thread = None
        if self.scaner_thread:
            self.scaner_thread.stop()
            self.scaner_thread = None

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon("main.ico"))
    window = MyWindow()
    window.show()
    sys.exit(app.exec())
